/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
/**
 * 
 */
package com.genia.toolbox.persistence.basis.manager;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import com.genia.toolbox.basics.bean.IterableIterator;
import com.genia.toolbox.basics.bean.impl.IterableIteratorImpl;
import com.genia.toolbox.persistence.basis.criteria.SimpleCriteriaResultIterable;
import com.genia.toolbox.persistence.bean.Persistable;
import com.genia.toolbox.persistence.bean.QueryParameters;
import com.genia.toolbox.persistence.bean.impl.QueryParametersImpl;
import com.genia.toolbox.persistence.criteria.Criteria;
import com.genia.toolbox.persistence.criteria.CriteriaResult;
import com.genia.toolbox.persistence.exception.ObjectIsNotPersistentException;
import com.genia.toolbox.persistence.exception.PersistenceException;
import com.genia.toolbox.persistence.exception.ResultIsNotUniqueException;
import com.genia.toolbox.persistence.manager.CrossSessionManager;
import com.genia.toolbox.persistence.manager.PersistenceManager;
import com.genia.toolbox.persistence.spring.manager.DependencyManager;

/**
 * This class represents a basis for the generic PersistenceManager.
 */
public abstract class AbstractPersistenceManager
    implements PersistenceManager
{

  /**
   * the {@link CrossSessionManager} to use with this {@link PersistenceManager}.
   */
  private CrossSessionManager crossSessionManager;

  /**
   * the <code>DependencyManager</code>.
   */
  private transient DependencyManager dependencyManager;



  /**
   * Convert an exception to an <code>PersistenceException</code>.
   * 
   * @param exception
   *          the exception to be converted
   * @return a <code>PersistenceException</code>
   */
  public PersistenceException convertException(final Exception exception)
  {
    if (exception instanceof PersistenceException) {
      return (PersistenceException) exception;
    }
    return new PersistenceException(exception);
  }



  /**
   * This method deletes an object if it is persistent, otherwise do nothing.
   * 
   * @param object
   *          The object to delete
   * @throws PersistenceException
   *           if any problems occur during persistence process
   */
  @SuppressWarnings("unchecked")
  public void deleteIfPersistent(Persistable<? extends Serializable> object)
      throws PersistenceException
  {
    if (get(object.getClass(), object.getIdentifier()) == null) {
      throw new ObjectIsNotPersistentException();
    }
    delete(object);
  }



  /**
   * This method returns the results of a criteria.
   * 
   * @param <MAINTYPE>
   *          the main type of the criteria
   * @param criteria
   *          the criteria that describes the query
   * @return the list of <code>CriteriaResult</code> that represents the
   *         result of the query
   * @throws PersistenceException
   *           when the is a problem with the persisence layer
   * @see com.genia.toolbox.persistence.manager.PersistenceManager#find(com.genia.toolbox.persistence.criteria.Criteria)
   */
  public <MAINTYPE> List<CriteriaResult<MAINTYPE>> find(Criteria<MAINTYPE> criteria)
      throws PersistenceException
  {
    return find(criteria, new QueryParametersImpl());
  }



  /**
   * This method returns the unique result of a criteria.
   * 
   * @param <MAINTYPE>
   *          the main type of the criteria.
   * @param criteria
   *          the criteria that describes the query
   * @return the <code>CriteriaResult</code> that represents the result of the
   *         query if there is an unique record, null if there is no record and throws a {@link ResultIsNotUniqueException} if there is more than one record
   * @throws PersistenceException
   *           when a persistence error occurred
   */
  public <MAINTYPE> CriteriaResult<MAINTYPE> findUnique(final Criteria<MAINTYPE> criteria)
      throws PersistenceException
  {
    final List<CriteriaResult<MAINTYPE>> results = find(criteria);
    if (results.isEmpty()) {
      return null;
    }
    if (results.size() != 1) {
      throw new ResultIsNotUniqueException();
    }
    return results.get(0);
  }



  /**
   * flush eventual cached elements. This implementation does nothing.
   * 
   * @see com.genia.toolbox.persistence.manager.PersistenceManager#clear()
   */
  public void clear()
  {
    // Do nothing.
  }



  /**
   * getter for the crossSessionManager property.
   * 
   * @return the crossSessionManager
   */
  public CrossSessionManager getCrossSessionManager()
  {
    return crossSessionManager;
  }



  /**
   * getter for the dependencyManager property.
   * 
   * @return the dependencyManager
   */
  public DependencyManager getDependencyManager()
  {
    return dependencyManager;
  }



  /**
   * This method iterates over the results of a criteria.
   * 
   * @param <MAINTYPE>
   *          the main type of the criteria
   * @param criteria
   *          the criteria that describes the query
   * @return the list of <code>CriteriaResult</code> that represents the
   *         result of the query
   * @throws PersistenceException
   *           when the is a problem with the persisence layer
   * @see com.genia.toolbox.persistence.manager.PersistenceManager#iterate(com.genia.toolbox.persistence.criteria.Criteria)
   */
  public <MAINTYPE> IterableIterator<CriteriaResult<MAINTYPE>> iterate(Criteria<MAINTYPE> criteria)
      throws PersistenceException
  {
    return iterate(criteria, new QueryParametersImpl());
  }



  /**
   * This method iterates over the results of a criteria.
   * 
   * @param <MAINTYPE>
   *          the main type of the criteria
   * @param criteria
   *          the criteria that describes the query
   * @param parameters
   *          the parameters of this search
   * @return the list of <code>CriteriaResult</code> that represents the
   *         result of the query
   * @throws PersistenceException
   *           when the is a problem with the persisence layer
   * @see com.genia.toolbox.persistence.manager.PersistenceManager#iterate(com.genia.toolbox.persistence.criteria.Criteria,
   *      com.genia.toolbox.persistence.bean.QueryParameters)
   */
  public <MAINTYPE> IterableIterator<CriteriaResult<MAINTYPE>> iterate(Criteria<MAINTYPE> criteria, QueryParameters parameters)
      throws PersistenceException
  {
    return new IterableIteratorImpl<CriteriaResult<MAINTYPE>>(find(criteria, parameters).iterator());
  }



  /**
   * setter for the crossSessionManager property.
   * 
   * @param crossSessionManager
   *          the crossSessionManager to set
   */
  public void setCrossSessionManager(CrossSessionManager crossSessionManager)
  {
    this.crossSessionManager = crossSessionManager;
  }



  /**
   * setter for the dependencyManager property.
   * 
   * @param dependencyManager
   *          the dependencyManager to set
   */
  public void setDependencyManager(final DependencyManager dependencyManager)
  {
    this.dependencyManager = dependencyManager;
  }



  /**
   * This method returns the main results of a criteria. The criteria must not
   * have any projection.
   * 
   * @param <MAINTYPE>
   *          the main type of the criteria
   * @param criteria
   *          the criteria that describes the query
   * @return the list of result
   * @throws PersistenceException
   *           when the is a problem with the persisence layer
   */
  public <MAINTYPE> List<MAINTYPE> simpleFind(final Criteria<MAINTYPE> criteria)
      throws PersistenceException
  {
    return simpleFind(criteria, new QueryParametersImpl());
  }



  /**
   * This method returns the main results of a criteria.
   * 
   * @param <MAINTYPE>
   *          the main type of the criteria
   * @param criteria
   *          the criteria that describes the query
   * @return the list of result
   * @param parameters
   *          the parameters of this search
   * @throws PersistenceException
   *           when the is a problem with the persisence layer
   * @see com.genia.toolbox.persistence.manager.PersistenceManager#simpleFind(com.genia.toolbox.persistence.criteria.Criteria,
   *      com.genia.toolbox.persistence.bean.QueryParameters)
   */
  public <MAINTYPE> List<MAINTYPE> simpleFind(Criteria<MAINTYPE> criteria, QueryParameters parameters)
      throws PersistenceException
  {
    final ArrayList<MAINTYPE> res = new ArrayList<MAINTYPE>();
    for (final CriteriaResult<MAINTYPE> criteriaResult : find(criteria, parameters)) {
      res.add(criteriaResult.get());
    }
    return res;
  }



  /**
   * This method returns the unique main results of a criteria.
   * 
   * @param <MAINTYPE>
   *          the main type of the criteria
   * @param criteria
   *          the criteria that describes the query
   * @return the unique result if there is an unique record, null if there is no record and throws a {@link ResultIsNotUniqueException} if there is more than one record
   * @throws PersistenceException
   *           when the is a problem with the persisence layer
   */
  public <MAINTYPE> MAINTYPE simpleFindUnique(final Criteria<MAINTYPE> criteria)
      throws PersistenceException
  {
    CriteriaResult<MAINTYPE> criteriaResult = findUnique(criteria);
    if (criteriaResult == null) {
      return null;
    }
    return criteriaResult.get();
  }



  /**
   * This method iterates over the main results of a criteria.
   * 
   * @param <MAINTYPE>
   *          the main type of the criteria
   * @param criteria
   *          the criteria that describes the query
   * @return the list of result
   * @throws PersistenceException
   *           when there is a problem with the persisence layer
   * @see com.genia.toolbox.persistence.manager.PersistenceManager#simpleIterate(com.genia.toolbox.persistence.criteria.Criteria)
   */
  public <MAINTYPE> IterableIterator<MAINTYPE> simpleIterate(Criteria<MAINTYPE> criteria)
      throws PersistenceException
  {
    return simpleIterate(criteria, new QueryParametersImpl());
  }



  /**
   * This method iterates over the main results of a criteria.
   * 
   * @param <MAINTYPE>
   *          the main type of the criteria
   * @param criteria
   *          the criteria that describes the query
   * @param parameters
   *          the parameters of this search
   * @return the list of result
   * @throws PersistenceException
   *           when the is a problem with the persisence layer
   * @see com.genia.toolbox.persistence.manager.PersistenceManager#simpleIterate(com.genia.toolbox.persistence.criteria.Criteria,
   *      com.genia.toolbox.persistence.bean.QueryParameters)
   */
  public <MAINTYPE> IterableIterator<MAINTYPE> simpleIterate(Criteria<MAINTYPE> criteria, QueryParameters parameters)
      throws PersistenceException
  {
    return new SimpleCriteriaResultIterable<MAINTYPE>(iterate(criteria, parameters));
  }

}
